package com.netintech.project.system.word.service.impl;

import com.netintech.project.system.word.mapper.SensitiveWordMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.*;

/**
 * @Description: 敏感词过滤
 * @Project：test
 * @author changjianbao
 * @date 2019年6月12日 下午2:28:32
 * @version 1.0
 */
@Service
public class SensitiveWordFilterServiceImpl {

	@Autowired
	private SensitiveWordMapper sensitiveWordMapper;

	private static Map sensitiveWordMap = new HashMap();

	/**最小匹配规则*/
	public static int minMatchTYpe = 1;

	/**
	 *在完成依赖项注入以执行任何初始化之后需要执行的方法。必须在类投入使用之前调用此方法。
	 * 加载数据库中的所有敏感词到内存当中
	 */
	@PostConstruct
	public void initialize() {
		addSensitiveWordToHashMap(this.sensitiveWordMapper.keyWordSet());
	}

	/**
	 * 读取敏感词库，将敏感词放入HashSet中，构建一个DFA算法模型
	 * 中 = {
	 *      isEnd = 0
	 *      国 = {<br>
	 *      	 isEnd = 1
	 *           人 = {isEnd = 0
	 *                民 = {isEnd = 1}
	 *                }
	 *           男  = {
	 *           	   isEnd = 0
	 *           		人 = {
	 *           			 isEnd = 1
	 *           			}
	 *           	}
	 *           }
	 *      }
	 *  五 = {
	 *      isEnd = 0
	 *      星 = {
	 *      	isEnd = 0
	 *      	红 = {
	 *              isEnd = 0
	 *              旗 = {
	 *                   isEnd = 1
	 *                  }
	 *              }
	 *      	}
	 *      }
	 * @author changjianbao
	 * @date 2019年6月12日 下午2:28:32
	 * @param keyWordSet  敏感词库
	 * @version 1.0
	 */
	public static void addSensitiveWordToHashMap(Set<String> keyWordSet) {
		//初始化敏感词容器，减少扩容操作
		sensitiveWordMap = new HashMap(keyWordSet.size());
		String key = null;
		Map nowMap = null;
		Map<String, String> newWorMap = null;
		//迭代keyWordSet
		Iterator<String> iterator = keyWordSet.iterator();
		while(iterator.hasNext()){
			//关键字
			key = iterator.next();
			nowMap = sensitiveWordMap;
			for(int i = 0 ; i < key.length() ; i++){
				//转换成char型
				char keyChar = key.charAt(i);
				//获取
				Object wordMap = nowMap.get(keyChar);
				//如果存在该key，直接赋值
				if(wordMap != null){
					nowMap = (Map) wordMap;
				} else{     //不存在则，则构建一个map，同时将isEnd设置为0，因为他不是最后一个
					newWorMap = new HashMap<>();
					//不是最后一个
					newWorMap.put("isEnd", "0");
					nowMap.put(keyChar, newWorMap);
					nowMap = newWorMap;
				}

				if(i == key.length() - 1){
					//最后一个
					nowMap.put("isEnd", "1");
				}
			}
		}
	}


	/**
	 * 判断文字是否包含敏感字符
	 * @author changjianbao
	 * @date 2019年6月12日 下午2:28:32
	 * @param txt  文字
	 * @param matchType  匹配规则&nbsp;1：最小匹配规则，2：最大匹配规则
	 * @return 若包含返回true，否则返回false
	 * @version 1.0
	 */
	public boolean isContaintSensitiveWord(String txt,int matchType){
		boolean flag = false;
		for(int i = 0 ; i < txt.length() ; i++){
			//判断是否包含敏感字符
			int matchFlag = this.checkSensitiveWord(txt, i, matchType);
			//大于0存在，返回true
			if(matchFlag > 0){
				flag = true;
			}
		}
		return flag;
	}

	/**
	 * 获取文字中的敏感词
	 * @author changjianbao
	 * @date 2019年6月12日 下午2:28:32
	 * @param txt 文字
	 * @param matchType 匹配规则&nbsp;1：最小匹配规则，2：最大匹配规则
	 * @return
	 * @version 1.0
	 */
	public Set<String> getSensitiveWord(String txt , int matchType){
		Set<String> sensitiveWordList = new HashSet<String>();

		for(int i = 0 ; i < txt.length() ; i++){
			//判断是否包含敏感字符
			int length = checkSensitiveWord(txt, i, matchType);
			//存在,加入list中
			if(length > 0){
				sensitiveWordList.add(txt.substring(i, i+length));
				//减1的原因，是因为for会自增
				i = i + length - 1;
			}
		}

		return sensitiveWordList;
	}

	/**
	 * 替换敏感字字符
	 * @author changjianbao
	 * @date 2019年6月12日 下午2:28:32
	 * @param txt
	 * @param matchType
	 * @param replaceChar 替换字符，默认*
	 * @version 1.0
	 */
	public String replaceSensitiveWord(String txt,int matchType,String replaceChar){
		String resultTxt = txt;
		//获取所有的敏感词
		Set<String> set = getSensitiveWord(txt, matchType);
		Iterator<String> iterator = set.iterator();
		String word = null;
		String replaceString = null;
		while (iterator.hasNext()) {
			word = iterator.next();
			replaceString = getReplaceChars(replaceChar, word.length());
			resultTxt = resultTxt.replaceAll(word, replaceString);
		}

		return resultTxt;
	}

	/**
	 * 获取替换字符串
	 * @author changjianbao
	 * @date 2019年6月12日 下午2:28:32
	 * @param replaceChar
	 * @param length
	 * @return
	 * @version 1.0
	 */
	private String getReplaceChars(String replaceChar,int length){
		String resultReplace = replaceChar;
		for(int i = 1 ; i < length ; i++){
			resultReplace += replaceChar;
		}

		return resultReplace;
	}

	/**
	 * 检查文字中是否包含敏感字符，检查规则如下
	 * @author changjianbao
	 * @date 2019年6月12日 下午2:28:32
	 * @param txt
	 * @param beginIndex
	 * @param matchType
	 * @return，如果存在，则返回敏感词字符的长度，不存在返回0
	 * @version 1.0
	 */
	public int checkSensitiveWord(String txt,int beginIndex,int matchType){
		//敏感词结束标识位：用于敏感词只有1位的情况
		boolean  flag = false;
		//匹配标识数默认为0
		int matchFlag = 0;
		char word = 0;
		Map nowMap = sensitiveWordMap;
		for(int i = beginIndex; i < txt.length() ; i++){
			word = txt.charAt(i);
			//获取指定key
			nowMap = (Map) nowMap.get(word);
			//存在，则判断是否为最后一个
			if(nowMap != null){
				//找到相应key，匹配标识+1
				matchFlag++;
				//如果为最后一个匹配规则,结束循环，返回匹配标识数
				if("1".equals(nowMap.get("isEnd"))){
					//结束标志位为true
					flag = true;
					//最小规则，直接返回,最大规则还需继续查找
					if(SensitiveWordFilterServiceImpl.minMatchTYpe == matchType){
						break;
					}
				}
			}else{     //不存在，直接返回
				break;
			}
		}
		//长度必须大于等于1，为词
		if(matchFlag < 2 || !flag){
			matchFlag = 0;
		}
		return matchFlag;
	}
}

